﻿namespace UnityEditorInternal
{
    using Mono.Unix;
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;

    public class Xcode4Controller : IDisposable
    {
        private Socket _socket;
        private const string NM = "/tmp/unityxplugin";

        public static string BuildProject()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.BuildProject) };
                controller.SendCommand(cmd);
                return controller.ReceiveResult();
            }
        }

        public static void CleanProject()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.CleanProject) };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
            }
        }

        public static void CloseAllOpenUnityProjects()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.CloseAllUnityProjects) };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
            }
        }

        public void Connect()
        {
            Log("Connecting to Xcode", new object[0]);
            EndPoint remoteEP = new UnixEndPoint("/tmp/unityxplugin");
            this._socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
            this._socket.ReceiveTimeout = 0x493e0;
            this._socket.Connect(remoteEP);
            Log("Connected", new object[0]);
        }

        private static string CreateCommand(Xcode4Commands cmd)
        {
            return Convert.ToString((int) cmd);
        }

        public void Disconnect()
        {
            Log("Disconnecting", new object[0]);
            if (this._socket != null)
            {
                this._socket.Close();
            }
            this._socket = null;
        }

        public void Dispose()
        {
            this.Disconnect();
        }

        public static string GetMobileDeviceList()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.MobileDeviceList) };
                controller.SendCommand(cmd);
                return controller.ReceiveResult();
            }
        }

        public static void Log(string msg, params object[] param)
        {
            Console.WriteLine(msg, param);
        }

        public static void OpenProject(string path)
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.OpenProject), path };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
                controller.WaitUntilActivitiesFinish();
            }
        }

        private string ReceiveResult()
        {
            List<byte> list = new List<byte>();
            byte[] buffer = new byte[1];
            int num = 0;
            do
            {
                num = this._socket.Receive(buffer);
                list.Add(buffer[0]);
            }
            while ((buffer[0] != 10) && (num > 0));
            string str = Encoding.UTF8.GetString(list.ToArray());
            Log(string.Format("Received results: {0}", str), new object[0]);
            return str;
        }

        public static void RunProject()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.RunProject) };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
            }
        }

        public static void SelectDeviceScheme()
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.SelectDeviceScheme) };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
            }
        }

        public static void SelectSimulatorScheme(string version)
        {
            using (Xcode4Controller controller = new Xcode4Controller())
            {
                controller.Connect();
                string[] cmd = new string[] { CreateCommand(Xcode4Commands.SelectSimulatorScheme), version };
                controller.SendCommand(cmd);
                controller.ReceiveResult();
            }
        }

        private void SendCommand(string[] cmd)
        {
            string str = string.Join("\t", cmd) + "\n";
            Log(string.Format("Sending command {0}", str), new object[0]);
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            this._socket.Send(bytes);
        }

        public static bool WaitForPluginStartup(int seconds)
        {
            object[] param = new object[] { seconds };
            Log("Waiting for Xcode plugin for up to {0} seconds", param);
            for (int i = 0; i < seconds; i++)
            {
                try
                {
                    using (Xcode4Controller controller = new Xcode4Controller())
                    {
                        controller.Connect();
                        Log("Successfully connected to the plugin", new object[0]);
                        return true;
                    }
                }
                catch (Exception)
                {
                }
                Thread.Sleep(0x3e8);
            }
            Log("Waiting for plugin timed out", new object[0]);
            return false;
        }

        private void WaitUntilActivitiesFinish()
        {
            string[] cmd = new string[] { CreateCommand(Xcode4Commands.WaitForActivitiesFinish) };
            this.SendCommand(cmd);
            this.ReceiveResult();
        }

        private enum Xcode4Commands
        {
            BuildProject = 9,
            CleanProject = 8,
            CloseAllUnityProjects = 1,
            MobileDeviceList = 10,
            OpenProject = 2,
            RunProject = 5,
            SelectDeviceScheme = 4,
            SelectSimulatorScheme = 3,
            Version = 7,
            WaitForActivitiesFinish = 6
        }
    }
}

